//-------------------------------------------------------------------------------------
// <copyright file="ShareTaskBase.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation. All rights reserved.
//      THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
//      EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
//      WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// </copyright>
// <author>Greg Beech</author>
// <email>gregbee@microsoft.com</email>
// <date>2004-04-20</date>
// <summary>
//      Base class for tasks that deal with shares.
// </summary>  
//-------------------------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Folder.Share
{
    #region Using directives

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Management;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Text;

    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
   
    #endregion

    /// <summary>
    /// Base class for tasks that deal with shares.
    /// </summary>
    public abstract class ShareTaskBase : TaskBase
    {
        #region Member Variables

        private string machine;
        private string password;
        private string shareName;
        private string username;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new share task base.
        /// </summary>
        protected ShareTaskBase()
        {
        }

        #endregion

        #region ShareType Enumeration

        /// <summary>
        /// The type of share. The value of the enumeration can be used in WMI Win32_Share methods.
        /// </summary>
        [CLSCompliant(false)]
        protected enum ShareType : uint
        {
            /// <summary>
            /// Disk drive.
            /// </summary>
            DiskDrive = 0x0,
            
            /// <summary>
            /// Print queue.
            /// </summary>
            PrintQueue = 0x1,
            
            /// <summary>
            /// Device.
            /// </summary>
            Device = 0x2,
            
            /// <summary>
            /// IPC.
            /// </summary>
            Ipc = 0x3,
            
            /// <summary>
            /// Disk drive admin.
            /// </summary>
            DiskDriveAdmin = 0x8000000,
            
            /// <summary>
            /// Print queue admin.
            /// </summary>
            PrintQueueAdmin = 0x8000001,
            
            /// <summary>
            /// Device admin.
            /// </summary>
            DeviceAdmin = 0x8000002,
            
            /// <summary>
            /// IPC admin.
            /// </summary>
            IpcAdmin = 0x8000003,
        }

        #endregion

        #region DeviceType Enumeration

        /// <summary>
        /// The type of a shared device. The value of the enumeration can be used in the Win32 Net* functions.
        /// </summary>
        [CLSCompliant(false)]
        protected enum DeviceType : uint
        {
            /// <summary>
            /// Any device type.
            /// </summary>
            Any = NativeMethods.USE_WILDCARD,
            
            /// <summary>
            /// A disk drive share.
            /// </summary>
            Disk = NativeMethods.USE_DISKDEV,
            
            /// <summary>
            /// A shared printer.
            /// </summary>
            Printer = NativeMethods.USE_SPOOLDEV,
            
            /// <summary>
            /// An IPC share.
            /// </summary>
            Ipc = NativeMethods.USE_IPC
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the name of the machine. The default is the local machine.
        /// </summary>
        /// <value>
        /// The name of the machine.
        /// </value>
        public virtual string Machine
        {
            get
            {
                return (this.machine == null) ? string.Empty : this.machine;
            }

            set
            {
                this.machine = value;
            }
        }

        /// <summary>
        /// Gets or sets the password used to connect to the machine.
        /// </summary>
        /// <value>
        /// The password used to connect to the machine.
        /// </value>
        public virtual string Password
        {
            get
            {
                return (this.password == null) ? string.Empty : this.password;
            }

            set
            {
                this.password = value;
            }
        }

        /// <summary>
        /// Gets or sets the name of the share.
        /// </summary>
        /// <value>
        /// The name of the share.
        /// </value>
        [Required]
        public virtual string ShareName
        {
            get
            {
                return (this.shareName == null) ? string.Empty : this.shareName;
            }

            set
            {
                this.shareName = value;
            }
        }

        /// <summary>
        /// Gets or sets the user name used to connect to the machine. This should be in the format DOMAIN\Username.
        /// </summary>
        /// <value>
        /// The user name used to connect to the machine.
        /// </value>
        public virtual string UserName
        {
            get
            {
                return (this.username == null) ? string.Empty : this.username;
            }

            set
            {
                if (value != null && value.Length > 0 && !value.Contains(@"\"))
                {
                    throw new FormatException(@"The user name must be in the format DOMAIN\Username.");
                }
                this.username = value;
            }
        }

        #endregion
       
        #region Internal Methods

        /// <summary>
        /// Gets the name of the invalid parameter in the USE_INFO_2 structure if the ERROR_INVALID_PARAMETER
        /// error is returned by one of the Net* functions.
        /// </summary>
        /// <param name="parameterIndex">
        /// The index of the invalid parameter that is filled in by the Net* function.
        /// </param>
        /// <returns>
        /// The friendly name of the invalid parameter.
        /// </returns>
        internal string GetUseInfoInvalidParameterFriendlyName(uint parameterIndex)
        {
            switch (parameterIndex)
            {
                case NativeMethods.USE_LOCAL_PARMNUM:
                    return "local device name";
                case NativeMethods.USE_REMOTE_PARMNUM:
                    return "share name";
                case NativeMethods.USE_PASSWORD_PARMNUM:
                    return "password";
                case NativeMethods.USE_ASGTYPE_PARMNUM:
                    return "device type";
                case NativeMethods.USE_USERNAME_PARMNUM:
                    return "user name";
                case NativeMethods.USE_DOMAINNAME_PARMNUM:
                    return "domain name";
                default:
                    return string.Format(CultureInfo.InvariantCulture, "unknown name (index = {0})", parameterIndex);
            }
        }

        /// <summary>
        /// Gets the value of the invalid parameter in the USE_INFO_2 structure if the ERROR_INVALID_PARAMETER
        /// error is returned by one of the Net* functions.
        /// </summary>
        /// <param name="useInfo">
        /// The USE_INFO_2 structure that was passed to the Net* function.
        /// </param>
        /// <param name="parameterIndex">
        /// The index of the invalid parameter that is filled in by the Net* function.
        /// </param>
        /// <returns>
        /// The value of the invalid parameter.
        /// </returns>
        internal object GetUseInfoInvalidParameterValue(NativeMethods.USE_INFO_2 useInfo, uint parameterIndex)
        {
            switch (parameterIndex)
            {
                case NativeMethods.USE_LOCAL_PARMNUM:
                    return useInfo.ui2_local;
                case NativeMethods.USE_REMOTE_PARMNUM:
                    return useInfo.ui2_remote;
                case NativeMethods.USE_PASSWORD_PARMNUM:
                    return useInfo.ui2_password;
                case NativeMethods.USE_ASGTYPE_PARMNUM:
                    return useInfo.ui2_asg_type;
                case NativeMethods.USE_USERNAME_PARMNUM:
                    return useInfo.ui2_username;
                case NativeMethods.USE_DOMAINNAME_PARMNUM:
                    return useInfo.ui2_domainname;
                default:
                    return string.Format(CultureInfo.InvariantCulture, "unknown value (index = {0})", parameterIndex);
            }
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Gets a connected management scope for the machine to create the share on.
        /// </summary>
        /// <returns>
        /// A connected management scope.
        /// </returns>
        protected ManagementScope GetManagementScope()
        {
            string machineName = (string.IsNullOrEmpty(this.machine)) ? "." : this.machine;
            string pathString = string.Concat(@"\\", machineName, @"\root\CIMv2");
            ManagementPath path = new ManagementPath(pathString);
            ManagementScope scope = new ManagementScope(path);
            scope.Options.Authentication = AuthenticationLevel.Default;
            scope.Options.EnablePrivileges = true;
            scope.Options.Impersonation = ImpersonationLevel.Impersonate;
            if (!string.IsNullOrEmpty(this.username))
            {
                scope.Options.Username = this.username;
                scope.Options.Password = this.password;
            }
            scope.Connect();
            return scope;
        }

        /// <summary>
        /// Gets the share path in the form \\machine\share.
        /// </summary>
        /// <returns>
        /// The share path in the form \\machine\share.
        /// </returns>
        protected string GetSharePath()
        {
            string machineName = (string.IsNullOrEmpty(this.machine)) ? Environment.MachineName : this.machine;
            return string.Concat(@"\\", machineName, @"\", this.ShareName);
        }

        #endregion
    }
}